﻿using System;
using System.Collections.Generic;
using System.Drawing;

namespace Common
{
    public class StatisticsDrawer
    {
        Color _labelColor = Color.FromArgb(0x00, 0xEA, 0xEA);
        Pen _pen = new Pen(Color.Aquamarine);
        Brush _brush = Brushes.Aquamarine;
        Font _font = new Font("Sans Serif", 10);
        Size _size = new Size(Point.Empty);
        int _leftMargin = 40;
        int _rightMargin = 20;
        int _bottomMargin = 40;
        int _topMargin = 10;

        double _maxValue = 60.0;
        double _step = 5.0;

        List<DataRow> _data = new List<DataRow>();
        IStatisticsDrawer _currentDrawer;

        /// <summary>Get or set the maximum value to show in the data grid.</summary>
        public double MaxValue { set { if (value > 0.0) _maxValue = value; } get { return _maxValue; } }
        /// <summary>Get or set the step size.</summary>
        public double Step { set { if (value > 0.0) _step = value; } get { return _step; } }

        public List<DataRow> Items {
            get { 
                lock (_data) {
                    return new List<DataRow>(_data);
                }
            }
        }
        public void AddItem(DataRow row) { lock (_data) { _data.Add(row); }  }

        public StatisticsDrawer()
        {
            _currentDrawer = new LineDrawer();
        }

        public void DrawGraph(Graphics g, Size size)
        {
            _size = size;
            DrawContext dc = new DrawContext(new Point(_leftMargin, GetDataArea().Top),
                                             g, GetDataArea().Width, GetDataArea().Height, MaxValue);

            DrawArea(g);
            DrawLeftLabels(g);
            DrawBottomLabels(g);
            _currentDrawer.DrawData(dc, Items);
        }

        private void DrawArea(Graphics g)
        {
            g.FillRectangle(Brushes.Black, new Rectangle(Point.Empty, _size));
            Rectangle area = GetDataArea();
            g.DrawRectangle(_pen, area.X - 1, area.Top - area.Height - 1, area.Width + 2, area.Height + 2);
        }

        private Rectangle GetDataArea()
        {
            Rectangle rect = new Rectangle(Point.Empty, _size);
            rect.Height -= _bottomMargin + _topMargin;
            rect.Width -= _leftMargin + _rightMargin;
            rect.X = _leftMargin;
            rect.Y = rect.Height + _topMargin;
            return rect;
        }

        private int GetInPixels(double value)
        {
            int height = GetDataArea().Height;
            return (int)(height / (MaxValue / value));
        }

        private void DrawBottomLabels(Graphics g)
        {
            const int padding = 10;
            Point location = new Point(GetDataArea().Left, _size.Height-20);
            foreach (DataRow item in _data)
            {
                location.X += DrawSingleBox(g, item, location);
                location.X += DrawSingleLabel(g, item, location);
                location.X += padding;
            }
        }

        private int DrawSingleBox(Graphics g, DataRow item, Point location)
        {
            const int boxWidth = 15;
            location.Y += 3;
            g.FillRectangle(new SolidBrush(item.Pen.Color), new Rectangle(location, new Size(11, 11)));
            return boxWidth;
        }

        private int DrawSingleLabel(Graphics g, DataRow item, Point location)
        {
            g.DrawString(item.Label, _font, _brush, location);
            return (int)g.MeasureString(item.Label, _font).Width;
        }

        private void DrawLeftLabels(Graphics g)
        {
            Rectangle location = GetDataArea();
            location.X -= 40;
            location.Y = location.Height;

            double val = 0.0;

            while (location.Y > 0)
            {
                g.DrawString(String.Format("{0:0.0}", val), _font, _brush, location);
                location.Y -= GetInPixels(Step);
                val += Step;
            }
        }
    }
}
